home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 April: Mac OS SDK / Dev.CD Apr 00 SDK1.toast / Development Kits / Mac OS / Open Transport 1.3 / Open Transport SDK / Open Tpt Client Developer / Samples / AppleTalk / PAPSample.cp < prev    next >
Encoding:
Text File  |  1998-04-30  |  28.2 KB  |  1,220 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        PAPSample.cp
  3.  
  4.     Contains:    Sample demonstration program for PAP
  5.  
  6.     Copyright:    © 1993-1996 by Apple Computer, Inc., all rights reserved.
  7.  
  8. */
  9.  
  10. #ifndef __OPENTPTGLOBALNEW__
  11. #include <OpenTptGlobalNew.h>
  12. #endif
  13. #ifndef __OPENTPTAPPLETALK__
  14. #include <OpenTptAppleTalk.h>
  15. #endif
  16. #ifndef __ATALKSAMPLEUTILS__
  17. #include "ATalkSampleUtils.h"
  18. #endif
  19. #ifndef __STDIO__
  20. #include <stdio.h>
  21. #endif
  22. #ifndef __EVENTS__
  23. #include <Events.h>
  24. #endif
  25. #ifndef __TEXTUTILS__
  26. #include <TextUtils.h>
  27. #endif
  28.  
  29. #define byName                1
  30. #define byAddr                0
  31.  
  32. const size_t kMaxRecv = 5000;          /*Max received data*/ 
  33. const size_t kMaxSend = 4096;          /*Max send data*/ 
  34. UInt8         gIncomingBuffer[kMaxRecv];
  35.  
  36. #if byName
  37. TNetbuf     gDestName;
  38. #endif
  39.  
  40. DDPAddress    gSLSAddr;
  41. DDPAddress    gConnAddr;
  42.  
  43. const size_t    kMaxReplyBufLen    = (512 * 8) + 4;
  44.  
  45. TEndpoint*     gEp            = NULL;
  46. TEndpoint*    gStatusEp    = NULL;
  47. Boolean     gConnectFlag = false;
  48. OSStatus     gConnectErr = 0;
  49. Boolean        gFlowControl = false;
  50. Boolean        gDone = false;
  51. Boolean        gEOF = false;
  52. /*
  53.  * We purposefully made gReadBuf not a multiple of 4K so that flow control
  54.  * would be a little less nice
  55.  */
  56. char        gReadBuf[10000];
  57. char*        gSendPtr;
  58. char*        gReadPtr;
  59. size_t        gBytesInBuf;
  60.  
  61. OTLIFO        gEventList;
  62.  
  63. UInt16        gStatSequence = 0;
  64. Boolean        gStatusAvailable = false;
  65. Boolean        gReadyForStatus = true;
  66. Boolean        gReceivedOrdRel = false;
  67. UInt8         gReplyBuffer[kMaxReplyBufLen];
  68. UInt8         gStatusBuffer[kMaxReplyBufLen];
  69. UInt8         gCurrentStatus[kMaxReplyBufLen]={0};
  70. size_t        gStatusLen, gCurrentStatusLen;
  71. UInt32        gNextStatusTime = 0;
  72.  
  73. /*******************************************************************************
  74. ** Structures
  75. ********************************************************************************/
  76.  
  77. class TOTEventItem
  78. {
  79.     public:
  80.                     inline TOTEventItem(void* ref, unsigned long code,
  81.                                          OTResult result, void* cookie)
  82.                     {
  83.                         fRef        = ref;
  84.                         fCode        = code;
  85.                         fResult        = result;
  86.                         fCookie        = cookie;
  87.                     };
  88.     OTLink            fLink;
  89.     void*            fRef;
  90.     unsigned long    fCode;
  91.     OTResult        fResult;
  92.     void*            fCookie;
  93. };
  94.  
  95. /*******************************************************************************
  96. ** Prototypes
  97. ********************************************************************************/
  98.  
  99. pascal    void        EventHandler(void*, OTEventCode, OTResult, void*);
  100.         OTResult    DoReceive(TEndpoint*, unsigned char*);
  101.         OTResult    DoRequestStatus(TEndpoint *ep, Boolean useName = false);
  102.         void        DoReadUReplies(TEndpoint*);
  103.         OSStatus    DoReadData( FILE* fp);
  104.         OSStatus    PollEventList();
  105.         OSStatus    DoBind(TEndpoint* ep, unsigned char socket, unsigned char type);
  106.         OSStatus    DoConnect(TEndpoint* ep);
  107.         OSStatus    DoSend(TEndpoint* ep);
  108.         TEndpoint*    CreatePAPEndpoint();
  109.         TEndpoint*    CreateATPEndpoint();
  110.         void        DoTest();
  111.  
  112. /*******************************************************************************
  113. ** EventHandler
  114. **  The event handler can be called at times when it is not safe to do console I/O,
  115. **  so this routine takes the event and jams it on a list to be handled when
  116. **  we know it's safe to print informative messages
  117. ********************************************************************************/
  118.  
  119. pascal void EventHandler(void* contextPtr, OTEventCode code,
  120.                                         OTResult result, void* cookie)
  121. {    
  122.     TOTEventItem* item = new TOTEventItem(contextPtr, code, result, cookie);
  123.  
  124.     if (item == NULL)
  125.     {
  126.         DebugStr("\pPAPTest: UniversalEventHandler -- could not allocate event structure");
  127.     }
  128.     else
  129.     {
  130.         gEventList.Enqueue(&item->fLink);
  131.     }
  132. }
  133.  
  134. /*******************************************************************************
  135. ** PollEventList
  136. **   This routine picks up the events received by EventHandler and processes them
  137. ********************************************************************************/
  138.  
  139. OSStatus PollEventList()
  140. {
  141.     OSStatus err = kOTNoError;
  142.  
  143.     if ( gStatusAvailable )
  144.     {
  145.         gReadyForStatus = true;
  146.         gStatusAvailable = false;
  147.         if ( gStatusLen > 0 )
  148.         {
  149.             if ( gCurrentStatusLen != gStatusLen ||
  150.                  !OTMemcmp(gCurrentStatus, gStatusBuffer + 8, gCurrentStatusLen) )
  151.             {
  152.                 size_t    offset = 1;
  153.             
  154.                 /*
  155.                  * Handle the fact that most printers return a "pascal" string, even though
  156.                  * this is not required.
  157.                  */
  158.                 gCurrentStatusLen = gStatusLen;
  159.                 OTMemcpy(gCurrentStatus, gStatusBuffer + 8, gStatusLen);
  160.                 if ( gStatusBuffer[8] != gStatusLen - 1 )
  161.                 {
  162.                     DebugStr("\pPollEvenList = status not pascal string");
  163.                     offset = 0;
  164.                 }
  165.                 fprintf(stderr, "### Status: '%*.*s'\n", gCurrentStatusLen - offset, gCurrentStatusLen - offset, 
  166.                         gCurrentStatus + offset);
  167.             }
  168.         }
  169.     }
  170.     while ( true )
  171.     {
  172.         OTLink* link = OTReverseList(gEventList.StealList());
  173.         
  174.         if ( link == NULL )
  175.             break;
  176.             
  177.         while ( link != NULL )
  178.         {
  179.             TOTEventItem* item = OTGetLinkObject(link, TOTEventItem, fLink);
  180.  
  181.             link = link->fNext;
  182.         
  183.             OTResult result = item->fResult;
  184.             void* cookie = item->fCookie;
  185.             int epNum  = (int)item->fRef;
  186.             if (epNum < 0 || epNum > 1)
  187.             {
  188.                 fprintf(stderr, "### Error:  PollEventList, Got bad refnum in event record");
  189.                 delete item;
  190.                 continue;
  191.             }
  192.  
  193.             TEndpoint* ep = epNum ? gStatusEp : gEp;
  194.  
  195.             switch (item->fCode )
  196.             {
  197.                 case T_DATA:
  198.                 {
  199.                     OTResult    result;
  200.                     fprintf(stderr, "### Info:  Received Message from printer\n");
  201.                     while ( (result = DoReceive(ep, gIncomingBuffer)) >= 0 )
  202.                     {
  203.                         if ( result != 0 )
  204.                             fprintf(stderr, "### Msg:    '%*.*s'\n", result, result, gIncomingBuffer);
  205.                     }
  206.                     break;
  207.                 }
  208.                 
  209.                 case T_CONNECT:
  210.                 {
  211.                     if ( result != 0 )
  212.                     {
  213.                         gConnectErr = result;
  214.                         err = result;
  215.                         break;
  216.                     }
  217. #if byName        
  218.                     TCall rcvCall;
  219.                     rcvCall.addr.maxlen = sizeof gConnAddr;
  220.                     rcvCall.addr.buf    = (UInt8*)&gConnAddr;
  221.                     rcvCall.opt.len        = 0;
  222.                     rcvCall.udata.len    = 0;
  223.                     err = ep->RcvConnect(&rcvCall);
  224. #endif
  225. #if byAddr
  226.                     err = ep->RcvConnect(NULL);
  227. #endif        
  228.                     if ( err != kOTNoError && err != kOTNoDataErr )
  229.                     {
  230.                         DebugStr("\pPAPSample: RcvConnect returns an error!");
  231.                         gConnectErr = err;
  232.                     }
  233.                     else
  234.                         gConnectFlag = true;
  235.         
  236.                     break;
  237.                 }
  238.                 
  239.                 case T_GODATA:
  240.                 {
  241.                     gFlowControl = false; // indicate that flow control has lifted
  242.                     fprintf(stderr, "### Info:   flow control OFF\n");
  243.                     break;
  244.                 }
  245.                     
  246.                 case T_ORDREL:
  247.                 {
  248.                     err = ep->RcvOrderlyDisconnect();
  249.                     if ( err != kOTNoError )
  250.                     {
  251.                         DebugStr("\pRcvOrderlyDisconnect failed.;g");
  252.                     }
  253.                     gReceivedOrdRel = true;
  254.                     break;
  255.                 }
  256.                 
  257.                 case T_DISCONNECT:
  258.                 {
  259.                     if ( cookie != NULL )            // A connect is rejected
  260.                     {
  261.                         if ( !gConnectFlag )
  262.                         {
  263.                             DebugStr("\pConnection attempt failed. Doing RcvDisconnect.;g");
  264.                             ep->RcvDisconnect(NULL);
  265.                             gConnectErr = -2; // special constant
  266.                         }
  267.                     }
  268.                     break;
  269.                 }
  270.                 
  271.                 case T_REPLY :
  272.                 {
  273.                     DoReadUReplies(ep);
  274.                     break;
  275.                 }
  276.                     
  277.                 case T_DISCONNECTCOMPLETE:
  278.                 {
  279.                     gReceivedOrdRel = true;
  280.                     break;
  281.                 }    
  282.                 
  283.                 default:
  284.                 {
  285.                     DebugStr("\pPAPSample: Unexpected Event!;g");
  286.                     break;
  287.                 }
  288.             }
  289.         }
  290.     }
  291.     return err;
  292. }
  293.  
  294. /*******************************************************************************
  295. ** DoBind
  296. ********************************************************************************/
  297.  
  298. OSStatus DoBind(TEndpoint* ep, unsigned char socket, unsigned char type)
  299. {
  300.     OSStatus err = kOTNoError;
  301.     
  302.     DDPAddress    addr;
  303.     addr.Init(0, 0, socket, type);        // Source address & type
  304.     
  305.     TBind                    req;
  306.     req.addr.buf    = (UInt8*)&addr;
  307.     req.addr.len    = kDDPAddressLength;
  308.     req.qlen        = 0;
  309.     
  310.     TBind                    ret;
  311.     
  312.     ret.addr.buf    = (UInt8*)&addr;
  313.     ret.addr.maxlen    = sizeof(addr);
  314.  
  315.     fprintf(stderr, "### Info:   Doing Bind\n");
  316.     //
  317.     // Try to bind
  318.     // 
  319.     err = ep->Bind(&req, &ret);
  320.     if ( err != kOTNoError )
  321.     {
  322.         fprintf(stderr, "### Error:  DoBind returns error %d\n", err);
  323.         return err;
  324.     }
  325.  
  326.     fprintf(stderr, "### Info:   Bound address = ");
  327.     ShowDDPAddress(&addr);
  328.     fprintf(stderr, "\n");
  329.     fprintf(stderr, "### Info:   Bound queue len is %d\n", ret.qlen);
  330.  
  331.     fprintf(stderr, "### Info:   After Bind, ");
  332.     ShowEndpointState(ep, "");
  333.  
  334.     return err;
  335. }
  336.  
  337. /*******************************************************************************
  338. ** DoConnect
  339. ********************************************************************************/
  340.  
  341. OSStatus DoConnect(TEndpoint* ep)
  342. {
  343.     TCall theCall;
  344.     static unsigned char optbuf[3 * kOTFourByteOptionSize];
  345.     
  346. #if byAddr
  347.     theCall.addr.buf    = (UInt8*)&gSLSAddr;
  348.     theCall.addr.len    = kDDPAddressLength;
  349. #endif
  350. #if byName
  351.     theCall.addr.buf    = gDestName.buf;
  352.     theCall.addr.len    = gDestName.len;
  353. #endif
  354.     
  355.     ((TOption*)optbuf)->len                = kOTFourByteOptionSize;
  356.     ((TOption*)optbuf)->level            = ATK_PAP;
  357.     ((TOption*)optbuf)->name            = PAP_OPT_OPENRETRY;
  358.     ((TOption*)optbuf)->value[0]        = 10;
  359.     (((TOption*)optbuf) + 1)->len        = kOTFourByteOptionSize;
  360.     (((TOption*)optbuf) + 1)->level        = ATK_PAP;
  361.     (((TOption*)optbuf) + 1)->name        = OPT_INTERVAL;
  362.     (((TOption*)optbuf) + 1)->value[0]    = 500;
  363. #if 0
  364.     (((TOption*)optbuf) + 2)->len        = kOTFourByteOptionSize;
  365.     (((TOption*)optbuf) + 2)->level        = ATK_ATP;
  366.     (((TOption*)optbuf) + 2)->name        = ATP_OPT_REPLYCNT;
  367.     (((TOption*)optbuf) + 2)->value[0]    = 1;
  368. #endif
  369.     theCall.opt.buf        = (UInt8*)optbuf;
  370. #if 0
  371.     theCall.opt.len        = 3 * kOTFourByteOptionSize;
  372. #else
  373.     theCall.opt.len        = 2 * kOTFourByteOptionSize;
  374. #endif
  375.     theCall.udata.len    = 0;
  376.     
  377.     gConnectFlag    = false;
  378.     gConnectErr        = 0;
  379.     OSStatus err = ep->Connect(&theCall, NULL);
  380.     if ( err != kOTNoError && err != kOTNoDataErr )
  381.     {
  382.         fprintf(stderr, "### Error:  Connect() returns %d\n", err);
  383.         if ( err == kOTLookErr )
  384.         {
  385.             
  386.             fprintf(stderr, "### Info:   Calling RcvDisconnect()...");
  387.             OSStatus err = ep->RcvDisconnect(NULL);
  388.             if ( err != kOTNoError )
  389.                 fprintf(stderr, "### Error:  RcvDisconnect returned %d\n", err);
  390.         }
  391.     }
  392.     else
  393.     {
  394.         err = kOTNoError;
  395.         Boolean flag = false;
  396.         while ( !gConnectFlag && !gConnectErr  && !(flag = Button()) )
  397.         {
  398.             OTIdle();
  399.             PollEventList();
  400.         }
  401.         
  402.         if ( flag )
  403.             err = -1; //%%% for now
  404.         else
  405.             err = gConnectErr;
  406.      }
  407.     return err;
  408. }
  409.  
  410. /*******************************************************************************
  411. ** DoRead
  412. ********************************************************************************/
  413.  
  414. OSStatus DoReadData(FILE* fp)
  415. {
  416.     while ( !gEOF && gBytesInBuf < sizeof(gReadBuf) )
  417.     {
  418.         size_t    toRead;
  419.         size_t    numRead;
  420.         
  421.         if ( gReadPtr >= gSendPtr )
  422.         {
  423.             toRead = gReadBuf + sizeof(gReadBuf) - gReadPtr;
  424.         }
  425.         else
  426.         {
  427.             toRead = gSendPtr - gReadPtr;
  428.         }
  429.         numRead = fread(gReadPtr, 1, toRead, fp); 
  430.         if ( numRead < 0 )
  431.         {
  432.             fprintf(stderr, "### Error:  Error %d reading file\n", numRead);
  433.             return (OSStatus)numRead;
  434.         }
  435.         printf("### Info:   Read %d bytes\n", numRead);
  436.         fflush(stdout);
  437.         gBytesInBuf += numRead;
  438.         gEOF = (numRead < toRead);
  439.         gReadPtr += numRead;
  440.         if ( gReadPtr >= gReadBuf + sizeof(gReadBuf) )
  441.         {
  442.             gReadPtr = gReadBuf;
  443.         }
  444.     }
  445.     return kOTNoError;
  446. }
  447.  
  448. /*******************************************************************************
  449. ** DoSend
  450. ********************************************************************************/
  451.  
  452. OSStatus DoSend(TEndpoint* ep)
  453. {
  454.     while ( gBytesInBuf > 0 )
  455.     {
  456.         size_t        toSend;
  457.         OTResult    numSent;
  458.  
  459.         /*
  460.          * If we're flow controlled or done, get out of here
  461.          */
  462.         if ( gFlowControl || gDone )
  463.             return 0;
  464.         /*
  465.          * Set up the number of bytes we can send
  466.          */
  467.         if ( gSendPtr >= gReadPtr )
  468.         {
  469.             toSend = gReadBuf + sizeof(gReadBuf) - gSendPtr;
  470.         }
  471.         else
  472.         {
  473.             toSend = gReadPtr - gSendPtr;
  474.         }
  475.         /*
  476.          * If there's nothing to send, get out of here, but handle
  477.          * the special case where gReadPtr == gSendPtr and gBytesInBuf is 
  478.          * the sizeof(gReadBuf).
  479.          */
  480.         if ( toSend == 0 )
  481.         {
  482.             if ( gBytesInBuf != sizeof(gReadBuf) )
  483.             {
  484.                 DebugStr("\pgBytesInBuf <> 0, but gReadPtr == gSendPtr");
  485.                 return 0;
  486.             }
  487.             toSend = gBytesInBuf;
  488.         }
  489.         /*
  490.          * Send the data
  491.          */
  492.         numSent = ep->Snd(gSendPtr, toSend, 0);
  493.         /*
  494.          * TO make the logic easier, treat a flow error as a 0-byte send
  495.          */
  496.         if ( numSent == kOTFlowErr )
  497.             numSent = 0;
  498.         /*
  499.          * If no error happened on the send, update everything
  500.          */
  501.         if ( numSent >= 0 )
  502.         {
  503.             gBytesInBuf -= numSent;
  504.             /*
  505.              * Update the send pointer
  506.              */
  507.             gSendPtr += numSent;
  508.             if ( gSendPtr >= gReadBuf + sizeof(gReadBuf) )
  509.                 gSendPtr = gReadBuf;
  510.             /*
  511.              * Show progress
  512.              */
  513.             if ( numSent > 0 )
  514.             {
  515.                 printf("### Info:   Sent %d bytes\n", numSent);
  516.                 fflush(stdout);
  517.             }
  518.             /*
  519.              * If we flow controlled, set the flags and split
  520.              */
  521.             if ( numSent < toSend )
  522.             {
  523.                 gFlowControl = true;
  524.                 printf("### Info:   flow control ON\n", ep);
  525.                 fflush(stdout);
  526.                 return 1;
  527.             }
  528.             /*
  529.              * Set up the flag that says we're done
  530.              */            
  531.             gDone = gEOF && gSendPtr == gReadPtr;
  532.             continue;
  533.         }
  534.         /*
  535.          * For a look error, we have to look - the only thing we should get is a T_DISCONNECT
  536.          */
  537.         if ( numSent == kOTLookErr )
  538.         {
  539.             OTResult    look;
  540.             
  541.             look = ep->Look();
  542.             switch ( look )
  543.             {
  544.                 case T_DISCONNECT:
  545.                 {
  546.                     fprintf(stderr, "### Info:   Got Look() returning T_DISCONNECT\n");
  547.                     look = ep->RcvDisconnect(NULL);
  548.                     if ( look < 0 )
  549.                         fprintf(stderr, "### Error:  RcvDisconnect returned %d\n", look);
  550.                     else
  551.                         gConnectFlag = false;
  552.                     return -1;
  553.                 }
  554.                 
  555.                 default:
  556.                     fprintf(stderr, "### Error:  Unexpected Look() return value - %d\n", look);
  557.                     return -3;
  558.             }
  559.         }
  560.         /*
  561.          * Here, we're clearly confused.  Return a -2 to the caller so he can close things
  562.          * down.
  563.          */
  564.         fprintf(stderr, "### ERROR:  Snd fails with %d\n", numSent);
  565.         return -2;
  566.     }
  567.     return kOTNoError;    
  568. }
  569.  
  570.  
  571. /*******************************************************************************
  572. ** DoReceive
  573. ********************************************************************************/
  574.  
  575. OTResult DoReceive(TEndpoint* ep, UInt8* buffer)
  576. {
  577.     OTFlags        flags = 0;
  578.     OTResult    result;
  579.     
  580.     result = ep->Rcv(buffer, kMaxRecv, &flags);
  581.     if ( result < 0 )
  582.     {
  583.         if ( result == kOTLookErr )
  584.         {
  585.             OTResult    look;
  586.             
  587.             look = ep->Look();
  588.             switch ( look )
  589.             {
  590.                 case T_DISCONNECT:
  591.                 {
  592.                     fprintf(stderr, "### Info:   Got Look() returning T_DISCONNECT\n");
  593.                     look = ep->RcvDisconnect(NULL);
  594.                     if ( look < 0 )
  595.                         fprintf(stderr, "### Error:  RcvDisconnect returned %d\n", look);
  596.                     else
  597.                         gConnectFlag = false;
  598.                     return -1;
  599.                 }
  600.                 
  601.                 default:
  602.                     fprintf(stderr, "### Error:  Unexpected Look() return value - %d\n", look);
  603.                     return -3;
  604.             }
  605.         }
  606.         else if ( result != kOTNoDataErr )
  607.         {
  608.             fprintf(stderr, "### Error:  OTRcv() returned %d\n", result);
  609.         }
  610.     }
  611.     return result;
  612. }
  613.  
  614. /*******************************************************************************
  615. ** DoReadUReplies
  616. ********************************************************************************/
  617.  
  618. void DoReadUReplies(TEndpoint* atpEp)
  619. {
  620.  
  621.     OSStatus    err;
  622.     OTFlags        flags;
  623.     
  624.     while ( true )
  625.     {
  626.         TUnitReply    reply;
  627.         
  628.         reply.opt.maxlen    = 0;
  629.         reply.udata.maxlen    = sizeof(gStatusBuffer);
  630.         reply.udata.buf        = gStatusBuffer;
  631.         
  632.         err = atpEp->RcvUReply(&reply, &flags);
  633.         
  634.         if ( err != kOTNoError )
  635.         {
  636.             if ( err == kOTNoDataErr )
  637.                 return;
  638.             if ( err != kETIMEDOUTErr )
  639.             {
  640.                 fprintf(stderr, "\nOTRcvUReply: returned error %d\n", err);
  641.                 return;
  642.             }
  643.         }
  644.         // If this is really the reply to our last request, save it.
  645.         if ( reply.sequence == gStatSequence )
  646.         {
  647.             if ( reply.udata.len <= 8 )
  648.                 gStatusLen = 0;
  649.             else
  650.             {
  651.                 gStatusLen = (size_t)reply.udata.len - 8;
  652.             }
  653.             gStatusAvailable = true;
  654.         }
  655.         
  656.     }
  657. }
  658.  
  659. /*******************************************************************************
  660. ** CreatePAPEndpoint
  661. ********************************************************************************/
  662.  
  663. TEndpoint* CreatePAPEndpoint()
  664. {
  665.     TEndpoint*    ep = NULL;
  666.     OSStatus    err = kOTNoError;
  667.  
  668.     do
  669.     {
  670.         //
  671.         // Create a PAP
  672.         //
  673.         ep = OTOpenEndpoint(OTCreateConfiguration(kPAPName), 0, NULL, &err);
  674.  
  675.         if ( ep == NULL || err != kOTNoError )
  676.         {
  677.             ep = NULL;
  678.             fprintf(stderr,"ERROR: OpenEndpoint(\"pap\") failed with %d\n", err);
  679.             break;
  680.         }
  681.         ep->SetSynchronous();
  682.  
  683.         //
  684.         // Install notifier we're going to use for testing
  685.         //
  686.         err = ep->InstallNotifier(EventHandler, NULL);
  687.         if ( err != kOTNoError )
  688.         {
  689.             fprintf(stderr, "ERROR: InstallNotifier() failed with %d\n", err);
  690.             break;
  691.         }
  692.  
  693.         ShowFullEndpointData(ep);
  694.         
  695.         return ep;
  696.  
  697.     } while ( false );
  698.     
  699.     if ( ep != NULL )
  700.         ep->Close();
  701.     
  702.     return NULL;
  703. }
  704.  
  705. /*******************************************************************************
  706. ** CreateATPEndpoint
  707. **  Note that this will be a synchronous endpoint, so we don't need a notifier.
  708. ********************************************************************************/
  709.  
  710. TEndpoint* CreateATPEndpoint()
  711. {
  712.     TEndpoint*    ep = NULL;
  713.     OSStatus    err = kOTNoError;
  714.  
  715.     do
  716.     {
  717.         //
  718.         // Create a PAP
  719.         //
  720.         ep = OTOpenEndpoint(OTCreateConfiguration(kATPName), 0, NULL, &err);
  721.  
  722.         if ( ep == NULL || err != kOTNoError )
  723.         {
  724.             ep = NULL;
  725.             fprintf(stderr,"ERROR: OpenEndpoint(\"atp\") failed with %d\n", err);
  726.             break;
  727.         }
  728.         ep->SetSynchronous();
  729.  
  730.         //
  731.         // Install notifier we're going to use for testing
  732.         //
  733.         err = ep->InstallNotifier(EventHandler, (void*)1);
  734.         if ( err != kOTNoError )
  735.         {
  736.             fprintf(stderr, "ERROR: InstallNotifier() failed with %d\n", err);
  737.             break;
  738.         }
  739.  
  740.         
  741.         return ep;
  742.  
  743.     } while ( false );
  744.     
  745.     if ( ep != NULL )
  746.         ep->Close();
  747.     
  748.     return NULL;
  749. }
  750.  
  751. /*******************************************************************************
  752. ** DoRequestStatus
  753. ********************************************************************************/
  754.  
  755. OTResult DoRequestStatus(TEndpoint *ep, Boolean useName)
  756. {
  757.     static UInt8 requestMsg[4] = {0, 8, 0, 0};
  758.     static unsigned char optbuf[3 * kOTFourByteOptionSize];
  759.     
  760.     TUnitRequest theReq;
  761.     
  762.     if ( useName )
  763.     {
  764.         theReq.addr.buf    = gDestName.buf;
  765.         theReq.addr.len    = gDestName.len;
  766.     }
  767.     else
  768.     {
  769.         theReq.addr.buf    = (UInt8*)&gSLSAddr;
  770.         theReq.addr.len    = kDDPAddressLength;
  771.     }
  772.     //
  773.     // We need to use the ATP_OPT_REPLY count option to specify that we're 
  774.     //  only expecting a single packet response, because there are printers
  775.     //  out there that don't set the EOM bit when they should.
  776.     //
  777.     ((TOption*)optbuf)->len                    = kOTFourByteOptionSize;
  778.     ((TOption*)optbuf)->level                = ATK_ATP;
  779.     ((TOption*)optbuf)->name                = ATP_OPT_REPLYCNT;
  780.     ((TOption*)optbuf)->value[0]            = 1;
  781.     (((TOption*)optbuf) + 1)->len            = kOTFourByteOptionSize;
  782.     (((TOption*)optbuf) + 1)->level            = ATK_ATP;
  783.     (((TOption*)optbuf) + 1)->name            = OPT_RETRYCNT;
  784.     (((TOption*)optbuf) + 1)->value[0]        = 2;                /* Retry 2 times */
  785.     (((TOption*)optbuf) + 2)->len            = kOTFourByteOptionSize;
  786.     (((TOption*)optbuf) + 2)->level            = ATK_ATP;
  787.     (((TOption*)optbuf) + 2)->name            = OPT_INTERVAL;
  788.     (((TOption*)optbuf) + 2)->value[0]        = 500;                /* 500 milisecond retries */
  789.     
  790.     theReq.opt.buf        = optbuf;    
  791.     theReq.opt.len        = 3 * kOTFourByteOptionSize;    
  792.     
  793.     theReq.udata.buf    = requestMsg;
  794.     theReq.udata.len    = sizeof requestMsg;
  795.     
  796.     theReq.sequence        = ++gStatSequence;
  797.     
  798.     gReadyForStatus = false;
  799.     OTResult err = ep->SndURequest(&theReq, 0);
  800.     
  801.     gNextStatusTime = TickCount()+120;            /* Next status in 2 seconds (allows for 1.5 seconds of retry time */
  802.     
  803.     if ( err != kOTNoError )
  804.         fprintf(stderr, "SndURequest returns %d\n", err);
  805.     
  806.     return err;
  807. }
  808.     
  809.  
  810. /*******************************************************************************
  811. ** DoTest
  812. ********************************************************************************/
  813.  
  814. void DoTest()
  815. {
  816.     OSStatus err = kOTNoError;
  817.     FILE *fp=NULL;
  818.  
  819.     do
  820.     {
  821.     /*    -------------------------------------------------------------------------
  822.         Create endpoint.
  823.         ------------------------------------------------------------------------- */
  824.  
  825.         gEp = CreatePAPEndpoint();
  826.          if ( gEp == NULL )
  827.          {
  828.              fprintf(stderr, "PAPSample: CreatePAPEndpoint for endpoint failed.\n", err);
  829.              break;
  830.          }
  831.  
  832. #if 0        
  833.         {
  834.             TOptMgmt    opt1, opt2;
  835.             TOption        buf1, buf2;
  836.             buf1.len = kOTFourByteOptionSize;
  837.             buf1.level = XTI_GENERIC;
  838.             buf1.name = XTI_RCVLOWAT;
  839.             buf1.value[0] = 0;
  840.             opt1.opt.buf = (UInt8*)&buf1;
  841.             opt1.opt.len = kOTFourByteOptionSize;
  842.             opt2.opt.maxlen = sizeof(TOption);
  843.             opt2.opt.buf = (UInt8*)&buf2;
  844.             opt1.flags = T_CURRENT;
  845.             if ( (err = gEp->OptionManagement(&opt1, &opt2)) != kOTNoError )
  846.             {
  847.                 fprintf(stderr, "PAPSample: get option failed (%d)\n", err);
  848.             }
  849.             else
  850.             {
  851.                 fprintf(stderr, "PAPSample: Status value was %d, value = %d\n",
  852.                         buf2.status, buf2.value[0]);
  853.                 buf1.len = kOTFourByteOptionSize;
  854.                 buf1.level = XTI_GENERIC;
  855.                 buf1.name = XTI_RCVLOWAT;
  856.                 buf1.value[0] = 0xc000;
  857.                 opt1.flags = T_NEGOTIATE;
  858.                 if ( (err = gEp->OptionManagement(&opt1, &opt2)) != kOTNoError )
  859.                 {
  860.                     fprintf(stderr, "PAPSample: set option failed (%d)\n", err);
  861.                 }
  862.                 else
  863.                 {
  864.                     fprintf(stderr, "PAPSample: Status value was %d, value = %d\n",
  865.                             buf2.status, buf2.value[0]);
  866.                 }
  867.                 opt1.flags = T_CURRENT;
  868.                 if ( (err = gEp->OptionManagement(&opt1, &opt2)) != kOTNoError )
  869.                 {
  870.                     fprintf(stderr, "PAPSample: get option failed (%d)\n", err);
  871.                 }
  872.                 else
  873.                 {
  874.                     fprintf(stderr, "PAPSample: Status value was %d, value = %d\n",
  875.                             buf2.status, buf2.value[0]);
  876.                 }
  877.                 
  878.             }
  879.  
  880.         }
  881.     #endif
  882.     
  883.         /*-------------------------------------------------------------------------
  884.         Bind endpoint.
  885.         ------------------------------------------------------------------------- */
  886.  
  887.         UInt8 socket    = 0;
  888.         UInt8 type        = 3;
  889.         
  890.         err = DoBind(gEp, socket, type);
  891.         if ( err != kOTNoError )
  892.         {
  893.             fprintf(stderr, "PAPSample: bind of PAP endpoint #1 failed.\n");
  894.             break;
  895.         }
  896.  
  897.         gEp->SetAsynchronous();
  898.         
  899.     /*    -------------------------------------------------------------------------
  900.         In order to get status from the printer, we have to use ATP. So let's open
  901.         and ATP endpoint.
  902.         ------------------------------------------------------------------------- */    
  903.  
  904.         gStatusEp = CreateATPEndpoint();
  905.          if ( gStatusEp == NULL )
  906.          {
  907.              fprintf(stderr, "PAPSample: CreateATPEndpoint for endpoint failed .\n", err);
  908.              break;
  909.          }
  910.         
  911.         /*-------------------------------------------------------------------------
  912.         Bind status endpoint.
  913.         ------------------------------------------------------------------------- */
  914.  
  915.         socket        = 0;
  916.         type        = 3;
  917.         
  918.         err = DoBind(gStatusEp, socket, type);
  919.         if ( err != kOTNoError )
  920.         {
  921.             fprintf(stderr, "PAPSample: bind of ATP endpoint #1 failed.\n");
  922.             break;
  923.         }
  924.  
  925.         gStatusEp->SetAsynchronous();
  926.         
  927.     /*    -------------------------------------------------------------------------
  928.         Run the test.
  929.         ------------------------------------------------------------------------- */
  930.         do
  931.         {
  932.             char fileName[256];
  933.             fprintf(stderr, "Enter name of input file:\n");
  934.             while ( true )
  935.             {
  936.                 gets(fileName);
  937.                 if ( fileName[0] != 0 )
  938.                     break;
  939.             }
  940.             
  941.             fp = fopen(fileName, "r");
  942.             if (fp == NULL)
  943.             {
  944.                 fprintf(stderr, "Couldn't open file %s\n", fileName);
  945.                 break;
  946.             }
  947.             
  948. #if byName
  949.             NBPAddress addr;
  950.             char addrBuf[64];
  951.         
  952.             fprintf(stderr, "Enter name to send to in form 'name:type@zone'\n");
  953.             while ( true )
  954.             {
  955.                 gets(addrBuf);
  956.                 if ( addrBuf[0] != 0 )
  957.                     break;
  958.             }
  959.             gDestName.buf    = (UInt8*)&addr;
  960.             gDestName.len    = addr.Init(addrBuf);
  961.             {
  962.                 TBind    inBind, outBind;
  963.                 inBind.addr.buf    = gDestName.buf;
  964.                 inBind.addr.len    = gDestName.len;
  965.                 outBind.addr.buf= (UInt8*)&gSLSAddr;
  966.                 outBind.addr.maxlen = kDDPAddressLength;
  967.                 gStatusEp->SetSynchronous();
  968.                 gStatusEp->SetBlocking();
  969.                 err = gStatusEp->ResolveAddress(&inBind, &outBind, 3000);
  970.                 if ( err != kOTNoError )
  971.                 {
  972.                     fprintf(stderr, "Could not find printer name\n");
  973.                     break;
  974.                 }
  975.                 gStatusEp->SetAsynchronous();
  976.             }
  977. #endif            
  978. #if byAddr
  979.             int net, node, socket;
  980.             
  981.             fprintf(stderr, "Enter the target network: ");
  982.             scanf("%x", &net);
  983.             fprintf(stderr, "Enter the target node: ");
  984.             scanf("%x", &node);
  985.             fprintf(stderr, "Enter the target socket: ");
  986.             scanf("%x", &socket);
  987.     
  988.             gSLSAddr.Init((UInt16)net, (UInt8)node, (UInt8)socket);
  989.             fprintf(stderr, "Target net node socket: %.4x  %.2x %.2x \n",net, node, socket);
  990. #endif    
  991.             //
  992.             // Connect
  993.             //
  994.             gEp->SetAsynchronous();
  995.             err = DoConnect(gEp);
  996.             if ( err != kOTNoError )
  997.             {
  998.                 if ( err == -2 )
  999.                     fprintf(stderr, "Connection attempt rejected\n");
  1000.                 else
  1001.                     fprintf(stderr, "DoConnect returned %d\n", err);
  1002.                     break;
  1003.             }
  1004.             //
  1005.             // See what our status looks like
  1006.             //
  1007.             DoRequestStatus(gStatusEp);    
  1008.             
  1009.         
  1010.             //
  1011.             // Try to Send some data
  1012.             // 
  1013.             fprintf(stderr, "Copying File:\n");
  1014.             
  1015.             gFlowControl = false;
  1016.             gDone = false;
  1017.             /*
  1018.              * Start off our circular buffer
  1019.              */
  1020.             gSendPtr    = gReadBuf;
  1021.             gReadPtr    = gReadBuf;
  1022.             gBytesInBuf    = 0;
  1023.             
  1024.             do
  1025.             {
  1026.                 err = DoReadData(fp);
  1027.                 if ( err < 0 )
  1028.                     break;
  1029.                 
  1030.                 err = DoSend(gEp);
  1031.                 if ( err < 0 )
  1032.                     break;
  1033.                 
  1034.                 OTIdle();
  1035.                 if ( gReadyForStatus && TickCount() >= gNextStatusTime)
  1036.                     DoRequestStatus(gStatusEp);
  1037.                 PollEventList();
  1038.                 /*
  1039.                  * gConnectFlag will get unset if we do an OTRcv() and
  1040.                  * a Connect came in.
  1041.                  */
  1042.                 if ( !gConnectFlag )
  1043.                     break;
  1044.             
  1045.             } while ( !gDone );
  1046.             fprintf(stderr, "\nWrite Complete\n");
  1047.  
  1048.         } while ( false );
  1049.         
  1050.         if ( gConnectFlag )
  1051.         {
  1052.             fprintf(stderr, "Press mouse to disconnect\n");
  1053.             while ( !Button() )                    // Wait for  mouse button
  1054.             {
  1055.                 OTIdle();
  1056.                 if (gReadyForStatus && TickCount() >= gNextStatusTime)
  1057.                     DoRequestStatus(gStatusEp);
  1058.                 PollEventList();
  1059.             }
  1060.             while ( Button() )                    // Wait 'til it's released
  1061.             {
  1062.                 OTIdle();
  1063.                 if (gReadyForStatus && TickCount() >= gNextStatusTime)
  1064.                     DoRequestStatus(gStatusEp);
  1065.                 PollEventList();
  1066.             }
  1067.                 
  1068.             //
  1069.             // Send Orderly Release
  1070.             // 
  1071.             gEp->SetSynchronous();
  1072.             fprintf(stderr, "### Info:   Sending orderly release\n");
  1073.             gReceivedOrdRel = false;
  1074.             err = gEp->SndOrderlyDisconnect();
  1075.             if ( err != kOTNoError )
  1076.             {
  1077.                 if ( err == kOTLookErr )
  1078.                 {
  1079.                     OTResult    look;
  1080.                     
  1081.                     fprintf(stderr,
  1082.                         "### Info:   SndOrderlyDisconnect returned a LOOK error\n");
  1083.  
  1084.                     look = gEp->Look();
  1085.                     switch ( look )
  1086.                     {
  1087.                         case T_DISCONNECT:
  1088.                         {
  1089.                             fprintf(stderr, "### Info:   Got Look() returning T_DISCONNECT\n");
  1090.                             look = gEp->RcvDisconnect(NULL);
  1091.                             if ( look < 0 )
  1092.                                 fprintf(stderr, "### Error:  RcvDisconnect returned %d\n", look);
  1093.                             else
  1094.                                 gConnectFlag = false;
  1095.                             break;
  1096.                         }
  1097.                         
  1098.                         default:
  1099.                             fprintf(stderr, "### Error:  Unexpected Look() return value - %d\n", look);
  1100.                             break;
  1101.                     }
  1102.                 }
  1103.                 else
  1104.                 {
  1105.                     fprintf(stderr,
  1106.                         "### Error:  SndOrderlyDisconnect failed with %d\n", err);
  1107.                 }
  1108.             }
  1109.             /*
  1110.              * If gConnectFlag is false - we got a Look while trying to disconnect and we're
  1111.              * disconnected by the underlying protocol, so don't wait for the orderly release
  1112.              */
  1113.             if ( gConnectFlag )
  1114.             {
  1115.                 fprintf(stderr, "### Info:   Waiting for orderly release acknowlegement - press mouse to abort\n");
  1116.                 while( !gReceivedOrdRel && !Button() )
  1117.                 {
  1118.                     OTIdle();
  1119.                     if (gReadyForStatus && TickCount() >= gNextStatusTime)
  1120.                         DoRequestStatus(gStatusEp);
  1121.                     PollEventList();
  1122.                 }
  1123.             }
  1124.             
  1125.             ShowEndpointState(gEp, "");
  1126.             
  1127.             fprintf(stderr, "### Info:   Press mouse to quit\n");
  1128.             while ( !Button() )                    // Wait for  mouse button
  1129.             {
  1130.                 OTIdle();
  1131.                 if (gReadyForStatus && TickCount() >= gNextStatusTime)
  1132.                     DoRequestStatus(gStatusEp);
  1133.                 PollEventList();
  1134.             }
  1135.             while ( Button() )                    // Wait 'til it's released
  1136.             {
  1137.                 OTIdle();
  1138.                 if (gReadyForStatus && TickCount() >= gNextStatusTime)
  1139.                     DoRequestStatus(gStatusEp);
  1140.                 PollEventList();
  1141.             }
  1142.         }
  1143.  
  1144.         
  1145.         //
  1146.         // Unbind
  1147.         //
  1148.         fprintf(stderr, "### Info:   About to Unbind()\n");
  1149.         err = gEp->Unbind();
  1150.         if ( err != kOTNoError )
  1151.         {
  1152.             fprintf(stderr, "### Error:  Unbind(pap) returned %d\n", err);
  1153.             break;
  1154.         }
  1155.         ShowEndpointState(gEp, "");
  1156.         
  1157.         err = gStatusEp->Unbind();
  1158.         if ( err != kOTNoError )
  1159.         {
  1160.             fprintf(stderr, "### Error:  Unbind(atp) returned %d\n", err);
  1161.             break;
  1162.         }
  1163.         ShowEndpointState(gStatusEp, "");
  1164.         
  1165.     } while (false);
  1166.  
  1167.     //
  1168.     // Get rid of endpoint.
  1169.     //
  1170.     if ( gStatusEp != NULL )
  1171.     {
  1172.         gStatusEp->RemoveNotifier();
  1173.         gStatusEp->Close();
  1174.     }    //
  1175.     // Get rid of endpoint.
  1176.     //
  1177.     if ( gEp != NULL )
  1178.     {
  1179.         gEp->RemoveNotifier();
  1180.         gEp->Close();
  1181.     }
  1182.     
  1183.     //
  1184.     // close our file
  1185.     //
  1186.     if ( fp != NULL )
  1187.         fclose(fp);
  1188.  
  1189. }
  1190.  
  1191. /*******************************************************************************
  1192. ** Initialize OpenTransport and call DoTest function
  1193. ********************************************************************************/
  1194.  
  1195. main(int, char**) 
  1196. {
  1197.     InitGraf(&qd.thePort);                    // initialize quickdraw so we can use regions
  1198.  
  1199.     fprintf(stderr, "PAPSample showing usage of PAP.\n\n");
  1200.     //
  1201.     // Initialize Open Transport
  1202.     //
  1203.     InitOpenTransport();
  1204.     //
  1205.     // Run the test
  1206.     //
  1207.     DoTest();
  1208.     //
  1209.     // Close Open Transport.
  1210.     // Not strictly necessary since it patches _ExitToShell and will
  1211.     // clean us up anyway.
  1212.     //
  1213.     CloseOpenTransport();
  1214.     
  1215.     fprintf(stderr, "\n\nDone\n");
  1216.         
  1217.     return 0;
  1218. };
  1219.  
  1220.